﻿/*************************************************************************
 *  Copyright (C), 2017-2018, YangTao tech. Co., Ltd.
 *  FileName: SocketServer.cs
 *  Author: YangTao   Version: 1.0   Date: 11/28/2016
 *  Email:YangTao_Unity3D@163.com
 *  Version Description:
 *    
 *  File Description:
 *    
 *  Class List:
 *    <ID>           <name>             <description>
 *     1.         SocketServer             
 *  Function List:
 *    <class ID>     <name>             <description>
 *     1.
 *  History:
 *    <ID>    <author>      <time>      <version>      <description>
 *     1.     YangTao     11/28/2016       1.0        Build this file.
 *************************************************************************/
using UnityEngine;
using System.Collections;

using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Text;
using System;
using System.Collections.Generic;

public class SocketServer
{
    /// <summary>服务端SOCKET</summary> 
    Socket m_serverSocket;
    /// <summary>存放消息数据</summary>
    byte[] m_msgBuffer;
    /// <summary>自身IP</summary> 
    IPAddress m_ip;
    /// <summary>端口号</summary> 
    int m_port;
    /// <summary>监听客户端连接线程</summary> 
    Thread m_listenThread;
    /// <summary>接收消息线程列表</summary> 
    List<Thread> m_recMsgThdList;
    /// <summary>处理消息线程</summary>
    Thread m_analyseThd;
    /// <summary>处理命令消息线程</summary>
    Thread m_analyseOrderThd;
    /// <summary>心跳包线程</summary>
    Thread m_heartbeatThd;
    /// <summary>监听个数</summary> 
    int m_listenCount;
    /// <summary>是否开启服务</summary> 
    bool m_isServerStart;
    /// <summary>是否接收消息</summary> 
    bool m_isReceiveMsg;
    /// <summary>是否处理消息</summary> 
    bool m_isAnalyseMsg;
    /// <summary>消息队列</summary> 
    public List<string> m_msgList;
    /// <summary>客户端管理</summary> 
    public ClientManage m_cliManage;
    /// <summary>消息管理</summary> 
    MsgManage m_msgManage;
    /// <summary>命令消息管理</summary> 
    OrderMsgManage m_orderMsgManage;
    /// <summary>从客户端收到消息</summary>
    public Void_StringStringStrListDelegate ReceiveMsgCallback;
    /// <summary>删除客户端</summary>
    public Void_ListStringDelegate DeletClientCallback;
    /// <summary>获得的消息头</summary>
    HeadSign m_head;
    /// <summary>获得的命令消息头</summary>
    OrderHeadSign m_orderHead;
    /// <summary>获得的IPList</summary>
    List<string> m_ipList;
    /// <summary>获得的命令IPList</summary>
    List<string> m_orderIPList;
    /// <summary>获得的消息（去掉标识）</summary>
    string m_content;
    /// <summary>服务端自身IP</summary>    
    public string m_serverIP;
    /// <summary>命令消息</summary> 
    List<string> m_orderList;//IPPORT ORDER_IPPORT

    /// <summary>初始化</summary>
    public void Init()
    {
        m_serverSocket = null;
        m_msgBuffer = new byte[2048];
        m_ip = IPAddress.Parse(Network.player.ipAddress);
        m_port = 8888;
        m_listenCount = 10;

        m_analyseThd = null;
        m_analyseOrderThd = null;
        m_listenThread = null;
        m_heartbeatThd = null;
        m_recMsgThdList = new List<Thread>();

        m_isServerStart = false;
        m_isAnalyseMsg = false;
        m_isReceiveMsg = false;

        m_msgList = new List<string>();
        m_orderList = new List<string>();

        m_cliManage = new ClientManage();
        m_msgManage = new MsgManage();
        m_orderMsgManage = new OrderMsgManage();

        m_head = HeadSign.DEFAULT;
        m_ipList = new List<string>();
        m_content = "";

        m_orderHead = OrderHeadSign.DEFAULT;
        m_orderIPList = new List<string>();
    }

    /// <summary>是否开启服务</summary>
    public bool InitNetwork()
    {
        if (m_isServerStart)
            return false;
        m_isServerStart = true;

        //服务器IP地址 
        if (m_serverSocket == null)
            m_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        m_serverSocket.Bind(new IPEndPoint(m_ip, m_port));//绑定IP地址：端口
        m_serverSocket.Listen(m_listenCount);//设定最多10个排队连接请求
        m_serverIP = m_serverSocket.LocalEndPoint.ToString();

        if (m_analyseThd == null)
            m_analyseThd = new Thread(AnalyseMsg);
        if (m_analyseOrderThd == null)
            m_analyseOrderThd = new Thread(AnalyseSendOrder);
        if (m_heartbeatThd == null)
            m_heartbeatThd = new Thread(Heartbeat);
        m_isAnalyseMsg = true;
        m_analyseThd.Start();
        m_analyseOrderThd.Start();
        m_heartbeatThd.Start();

        m_isReceiveMsg = true;
        m_listenThread = new Thread(ListenClientConnect);
        m_listenThread.Start();//开启线程  
        Debug.Log("启动监听成功");
        return true;
    }

    /// <summary>监听客户端连接</summary>  
    void ListenClientConnect()
    {
        while (m_isServerStart)
        {
            Debug.Log("外循环----");
            Socket newSocket = m_serverSocket.Accept();
            m_cliManage.AddClient(newSocket);//将连接的客户端添加进字典进行管理  

            Thread recMsgThread = new Thread(ReceMsg);
            recMsgThread.Start(newSocket);
            m_recMsgThdList.Add(recMsgThread);
            m_orderList.Add("AddClient" + "_" + newSocket.RemoteEndPoint.ToString());
        }
    }

    /// <summary>接收客户端消息</summary>
    public void ReceMsg(object obj)
    {
        Socket socket = (Socket)obj;
        while (m_isReceiveMsg)
        {
            try
            {
                int len = socket.Receive(m_msgBuffer);
                string msg = Encoding.UTF8.GetString(m_msgBuffer, 0, len);//收到的消息（包括头） 
                if (len == 0)
                {
                    Debug.Log("客户端断开");
                    CloseNetwork();
                    break;
                }
                m_msgList.Add(msg);
            }
            catch
            {
                Debug.Log("服务器接收数据异常");
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
                break;
            }
        }
    }

    /// <summary>解析消息</summary>
    void AnalyseMsg()
    {
        while (m_isAnalyseMsg)
        {
            Thread.Sleep(100);
            if (m_msgList.Count > 0)
            {
                if (m_msgManage.AnalysisMsg(m_msgList[0]))//解析消息
                {
                    m_head = m_msgManage.GetHeadSign();
                    m_ipList = m_msgManage.GetIPPortList();
                    m_content = m_msgManage.GetContent();

                    DealWithMsgCondition();
                }
                else if (m_orderMsgManage.AnalysisMsg(m_msgList[0]))//解析命令
                {
                    m_orderHead = m_orderMsgManage.GetOrderHeadSign();
                    m_orderIPList = m_orderMsgManage.GetIPPortList();

                    DealWithOrderMsgCondition();
                }

                m_msgList.RemoveAt(0);
            }
        }
    }

    /// <summary>判断转发类型并发送</summary>
    void DealWithMsgCondition()
    {
        string sendFrom = m_ipList[0];
        if (m_head == HeadSign.TOCLIENT)
        {
            List<string> list = new List<string>();
            list.Add(m_ipList[0]);
            string str = m_msgManage.GetMsg(HeadSign.STOC, m_content, list);
            m_ipList.RemoveAt(0);
            SendMsg(m_ipList, str);
        }
        else if (m_head == HeadSign.TOSERVER)
        {

        }
        else if (m_head == HeadSign.TOALL)//m_ipList中只有发送方名字
        {
            string str = m_msgManage.GetMsg(HeadSign.STOC, m_content, m_ipList);
            List<string> list = m_cliManage.GetAllClientIPPort();
            list.Remove(m_ipList[0]);
            SendMsg(list, str);
        }
        else if (m_head == HeadSign.STOC)
        {

        }
        else if (m_head == HeadSign.HEARTBEAT)
        {
            m_cliManage.ChangeClientHeart(m_ipList[0]);
            //string str = m_msgManage.GetMsg(HeadSign.HEARTBEAT, m_content, m_ipList);
            //SendMsg(m_ipList, str);
        }

        ReceiveMsgCallback(sendFrom, m_content, m_ipList);//通知界面显示发送方和接收方消息
    }

    /// <summary>判断命令类型</summary>
    void DealWithOrderMsgCondition()
    {
        if (m_orderHead == OrderHeadSign.DELETCLIENT)//客户端目前发送的增删消息只有一个IPPort，也就是本身
        {
            m_orderList.Add("DeletClient" + "_" + m_orderIPList[0]);
        }
    }

    public void SendContent(List<string> ipPortList, string content)
    {
        List<string> list = new List<string>();
        list.Add(m_serverIP);
        string str = m_msgManage.GetMsg(HeadSign.STOC, content, list);
        SendMsg(ipPortList, str);
    }

    /// <summary>
    /// 发送消息给链表中客户端
    /// </summary>
    /// <param name="ipPortList">客户端IP链表</param>
    /// <param name="msg">消息（包括头）</param>
    void SendMsg(List<string> ipPortList, string msg)
    {
        for (int i = 0; i < ipPortList.Count; i++)
        {
            Socket socket = m_cliManage.FindClient(ipPortList[i]);
            if (socket != null)
                socket.Send(Encoding.UTF8.GetBytes(msg));
        }
    }

    /*线程处理的原因，因为增加的客户端和删除的客户端处理位置不一样，导致先后顺序不一样，
     * 所以用list可以以堆栈的形式解决时间问题*/
    /// <summary>判断并发送命令</summary>
    void AnalyseSendOrder()
    {
        while (m_isAnalyseMsg)
        {
            if (m_orderList.Count > 0)
            {
                int index = m_orderList[0].IndexOf('_');//第一个'_'处的索引
                string head = m_orderList[0].Substring(0, index);//取出第一个'_'前字符
                string ipPort = m_orderList[0].Substring(index + 1);//去除'head_'后的字符

                if (head == "AddClient")
                {
                    List<string> Synlist = new List<string>();
                    PreDefScrp.ListDeepCopy(m_cliManage.GetAllClientIPPort(), out Synlist);
                    if (Synlist == null)
                        break;

                    if (Synlist.Count > 0)
                    {
                        if (Synlist.Contains(ipPort))
                            Synlist.Remove(ipPort);
                        else
                            break;

                        if (Synlist.Count > 0)
                        {
                            //对新增的客户端同步已有在线列表
                            string order = m_orderMsgManage.GetMsg(OrderHeadSign.ADDCLIENT, Synlist);
                            List<string> recvlist = new List<string>();//接收方链表
                            recvlist.Add(ipPort);
                            SendOrder(recvlist, order);

                            //把新增的客户端发送给已有客户端
                            order = m_orderMsgManage.GetMsg(OrderHeadSign.ADDCLIENT, recvlist);
                            SendOrder(Synlist, order);

                            recvlist.Clear();
                            recvlist = null;
                        }
                    }

                    Synlist.Clear();
                    Synlist = null;
                }
                else if (head == "DeletClient")
                {
                    List<string> Synlist = new List<string>();
                    Synlist.Add(ipPort);
                    string order = m_orderMsgManage.GetMsg(OrderHeadSign.DELETCLIENT, Synlist);
                    m_cliManage.DeleteClient(ipPort);
                    List<string> recvlist = m_cliManage.GetAllClientIPPort();
                    if (recvlist != null)
                        SendOrder(recvlist, order);
                    List<string> list = new List<string>();
                    list.Add(ipPort);
                    DeletClientCallback(list);
                }

                m_orderList.RemoveAt(0);
            }
        }
    }

    /// <summary>发送命令</summary>///
    void SendOrder(List<string> ipPortList, string order)
    {
        if (ipPortList == null)
            return;
        for (int i = 0; i < ipPortList.Count; i++)
        {
            Socket socket = m_cliManage.FindClient(ipPortList[i]);
            if (socket != null)
                socket.Send(Encoding.UTF8.GetBytes(order));
        }
    }

    void Heartbeat()
    {
        while (m_isAnalyseMsg)
        {
            Thread.Sleep(4000);
            Debug.Log("检测离线客户端");
            try
            {
                List<string> leaveIPList = m_cliManage.FindLeaveClient();
                if (leaveIPList.Count > 0)
                {
                    List<string> list = new List<string>();
                    list = m_cliManage.GetAllClientIPPort();
                    PreDefScrp.ListRemove(leaveIPList, ref list);
                    if (list.Count > 0)
                    {
                        string str = m_orderMsgManage.GetMsg(OrderHeadSign.DELETCLIENT, leaveIPList);
                        SendOrder(list, str);
                        DeletClientCallback(leaveIPList);
                    }
                }
            }
            catch (Exception e)
            {
                Debug.Log(e);
            }
        }
    }

    /// <summary>关闭Socket及线程</summary>
    public void CloseNetwork()
    {
        m_isServerStart = false;
        m_isReceiveMsg = false;
        m_isAnalyseMsg = false;

        m_cliManage.CloseAllSocket();
        if (m_serverSocket != null)
            m_serverSocket.Close();

        if (m_listenThread != null)
            m_listenThread.Abort();
        if (m_heartbeatThd != null)
            m_heartbeatThd = null;

        foreach (Thread thd in m_recMsgThdList)
        {
            if (thd != null)
                thd.Abort();
        }

        if (m_analyseThd != null)
            m_analyseThd.Abort();
        if (m_analyseOrderThd != null)
            m_analyseOrderThd.Abort();

        m_recMsgThdList.Clear();
    }
}